/*
 * EvoAlghorithm.h
 *
 *  Created on: 15.11.2012
 *      Author: shadius
 */

#ifndef EVOALGHORITHM_H_
#define EVOALGHORITHM_H_
#define CROSS_RATE 1.0
#define MIN_MUTATION_RATE 0.02
#define MUTATION_STEP 0.01
#define MAX_MUTATION_RATE 0.16

#define	 POPULATION_SIZE 100
#define	 PARAMETER_COUNT 5
#define	 GENERATIONS_NUM 5000
#define	 PI 0
#define	 CGI 1
#define	 CI 2
#define	 KI 3
#define	 DTI 4
#define PARAM_P_DEFAULT_MIN 0.8
#define PARAM_P_DEFAULT_MAX 1.2

#define PARAM_DT_DEFAULT_MIN 0
#define PARAM_DT_DEFAULT_MAX 40*60 //40 minutes in seconds
#define PARAM_CG_DEFAULT_MIN -10
#define PARAM_CG_DEFAULT_MAX 0
#define PARAM_C_DEFAULT_MIN 0
#define PARAM_C_DEFAULT_MAX 10
#include "IFastDataApprox.h"
#include <boost/numeric/ublas/matrix.hpp>
#include <iostream>
#include <memory>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <algorithm>
#include <vector>
#include <math.h>
#include "TimeUtils.h"
using namespace std;

typedef struct _RESULT {
    double p;
    double cg;
    double c;
    double k;
    double dt;
} RESULT, *LRESULT;

typedef struct _INPUT_PARAMS {
	string inputFile;
	int threadCount;
	double dtMin;
	double dtMax;
	bool isKset;
	double kMin;
	double kMax;
	bool isCset;
	double c;
	bool isPset;
	double p;

} INPUT_PARAMS;

typedef struct _THREAD_RESULTS {
    double bestFitness;
    double bestFitnessIdx;
    double minFitness;
} THREAD_RESULTS, *LTHREAD_RESULTS;

class EvoAlghorithm {
public:
	RESULT compute(LPAPPROXPOINT bgAPPROXPOINTS, LPAPPROXPOINT igAPPROXPOINTS, int len);
	EvoAlghorithm(const shared_ptr<IFastDataApprox> &BGValues,
			const shared_ptr<IFastDataApprox> &IGValues, const shared_ptr<vector<double>> p_ECGValues, INPUT_PARAMS params);
	//double randomGauss();

	virtual ~EvoAlghorithm();
private:
	shared_ptr<IFastDataApprox> p_BGValues;
	shared_ptr<IFastDataApprox> p_IGValues;
	shared_ptr<boost::numeric::ublas::matrix<double>> p_population;
	shared_ptr<vector<double>> p_fitness;
	shared_ptr<vector<double>> p_ECGValues;
	INPUT_PARAMS params;
	void fitnessParalel(int i, int offset, LTHREAD_RESULTS results, LPAPPROXPOINT bgAPPROXPOINTS,LPAPPROXPOINT igAPPROXPOINTS, int len);
	void initializePopulation();
	void mutate(double& mutationRate,
			shared_ptr<boost::numeric::ublas::matrix<double> >& p_newPopulation,
			int& iInd);

	double fitness(int iInd, LPAPPROXPOINT bgAPPROXPOINTS,
			LPAPPROXPOINT igAPPROXPOINTS, int len);
	int pickRandomIndividuum(double sumFitness);
	double getClosestBound(double min, double max, double num);
	double random();
	double random(double min, double max);
	bool checkRange(int index, double value);
	bool checkRangeP(double p);
	bool checkRangeCG(double cg);
	bool checkRangeDT(double dt);
	bool checkRangeC(double c);
	//double getRandomDoubleUsingNormalDistribution(double mean, double sigma);
	HRESULT countAverage(LPAPPROXPOINT bgAPPROXPOINTS,
			LPAPPROXPOINT igAPPROXPOINTS, double p, double cg, double c,
			double dt, double k, int len, double *sum, int *count);
	bool checkTimeJumpRange(double k, double dt, double ecg);
	void findKandDT(double *k, double *dt);
};

#endif /* EVOALGHORITHM_H_ */
